package com.slearing.databaseinfoserver.service;

import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.slearing.databaseinfoserver.enums.DbType;
import com.slearing.databaseinfoserver.utils.DataSourceUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.ai.tool.annotation.Tool;
import org.springframework.ai.tool.annotation.ToolParam;
import org.springframework.stereotype.Service;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;

/**
 * 提供表查询工具的服务类
 */
@Service
public class TableInfoService {
    Logger log = LoggerFactory.getLogger(TableInfoService.class);

    /**
     * 获取指定数据库类型的查询表名、模式名和表描述的SQL
     * 
     * @param dbType 数据库类型
     * @return 查询表名、模式名和表描述的SQL
     */
    private String getDbTypeSql(DbType dbType) {
        switch (dbType) {
            case MYSQL:
                return "SELECT table_schema, table_name, table_comment FROM information_schema.tables WHERE table_schema = DATABASE()";
            case ORACLE:
            case DM:
                return "SELECT t.owner, t.table_name, c.comments FROM all_tables t LEFT JOIN all_tab_comments c ON t.owner = c.owner AND t.table_name = c.table_name WHERE t.owner = USER";
            default:
                return null;
        }
    }

    /**
     * 查询所有数据源的表名、模式名和表描述，支持按表描述模糊过滤，返回JSON字符串。
     * 实现步骤：
     * 1. 从环境变量 DATA_SOURCE_INFO 获取所有数据源的连接信息（JSON数组）。
     * 2. 遍历每个数据源，解析出 url、username、password、driverClassName。
     * 3. 根据 driverClassName 判断数据库类型，获取对应的查询SQL。
     * 4. 连接数据库，执行SQL，查询出模式名、表名、表描述。
     * 5. 按表描述（tableDesc）进行模糊过滤，组装表信息到列表。
     * 6. 最终返回JSON字符串，包含 status、message、表列表（表名、表描述、数据库名）。
     * 7. 如遇异常，status为失败，message附带错误信息，表列表为空。
     * @param tableDesc 表的中文描述（可选，模糊匹配）
     * @return JSON字符串，包含status、message、表列表
     */
    @Tool(name = "findAllTableName",description = "查询所有的表名、模式名和表描述，返回提取表名的Prompt")
    public String findAllTableName(@ToolParam(description = "表的中文描述") String tableDesc) {
        // 从环境变量中获取数据库连接信息
        String dataSourceInfo = System.getenv("DATA_SOURCE_INFO");
        log.info("开始查询所有表名，表描述过滤条件: {}", tableDesc);
        log.debug("环境变量 DATA_SOURCE_INFO: {}", dataSourceInfo);
        // 提示词模板
        String message = "从下面表列表中查找出来满足【" + tableDesc + "】描述的表名，用md的表格格式返回";
        JSONArray tableList = new JSONArray();
        String status = "成功";
        try {
            if (dataSourceInfo == null) {
                status = "失败";
                log.error("未获取到环境变量 DATA_SOURCE_INFO");
                return toJson(status, "没有找到数据库连接信息", null);
            }

            // 遍历所有的数据源列表获取表名、模式名和表描述
            JSONArray dsList = JSONUtil.parseArray(dataSourceInfo);
            log.info("解析到{}个数据源", dsList.size());
            for (int i = 0; i < dsList.size(); i++) {
                JSONObject ds = dsList.getJSONObject(i);
                String url = ds.getStr("url");
                String username = ds.getStr("username");
                String password = ds.getStr("password");
                String driverClassName = ds.getStr("driverClassName");
                log.info("处理第{}个数据源，url: {}, username: {}, driverClassName: {}", i + 1, url, username, driverClassName);
                DbType dbType = DbType.fromDriverClassName(driverClassName);

                if (dbType == null) {
                    status = "失败";
                    log.error("数据源{}: 不支持的数据库类型 driverClassName={}。", i + 1, driverClassName);
                    return toJson(status, "数据源" + (i + 1) + ": 不支持的数据库类型", null);
                }

                // 获取指定数据库类型的查询表名、模式名和表描述的SQL
                String sql = getDbTypeSql(dbType);
                if (sql == null) {
                    status = "失败";
                    log.error("数据源{}: 未配置SQL，dbType={}", i + 1, dbType);
                    return toJson(status,  "数据源" + (i + 1) + ": 未配置SQL", null);
                }
                Connection conn = null;
                try {
                    log.info("尝试连接数据库: url={}, username={}, driverClassName={}", url, username, driverClassName);
                    conn = DataSourceUtil.getConnection(driverClassName, url, username, password);
                    log.info("数据库连接成功");
                    try (PreparedStatement ps = conn.prepareStatement(sql); ResultSet rs = ps.executeQuery()) {
                        log.debug("执行SQL: {}", sql);
                        while (rs.next()) {
                            String schema = rs.getString(1);
                            String tName = rs.getString(2);
                            String tComment = rs.getString(3);
                            if(StrUtil.isBlank(tComment)){
                                continue;
                            }
                            JSONObject tableInfo = new JSONObject();
                            tableInfo.set("表名", tName);
                            tableInfo.set("表描述", tComment == null ? "" : tComment);
                            tableInfo.set("数据库名", schema);
                            tableList.add(tableInfo);
                        }
                        log.info("数据源{}: 查询到{}张表", i + 1, tableList.size());
                    }
                } finally {
                    DataSourceUtil.closeQuietly(conn);
                    log.debug("数据库连接已关闭");
                }
            }
        } catch (Exception e) {
            status = "失败";
            log.error("查询所有表名异常: {}", e.getMessage(), e);
            return toJson(status, "解析数据库连接信息失败: " + e.getMessage() , null);
        }
        log.info("查询所有表名完成，status: {}，共{}张表", status, tableList.size());
        return toJson(status, message, tableList);
    }

    /**
     * 构造返回的JSON字符串，表列表用JSONArray
     */
    private String toJson(String status, String message, JSONArray tableList) {
        JSONObject result = new JSONObject();
        result.set("status", status);
        result.set("message", message);
        result.set("表列表", tableList);
        return result.toString();
    }
}
